import { IAllPosition, IValue, IExcelValue, IPositionValue, IGetRangeValues, IRange, IValueBase, TData, IRow } from './types';
import { FormulaError } from './formula-error';
import {  Injectable, InjectByName, InjectFactory } from '../../decorators/inject';
import { transformBaseValueToFormulaValue } from './utils';
import { IPosition, IPositionFullCol, IPositionFullRow } from '../formula.v2';
import { ITableDatas } from '../../cors/table-datas.interface';
import { Cell } from '../../cors/cell';

export class Range {
	type: 'range' = 'range';
	value!: { getValues: () => IValueBase[]; getMatrixValues: () => IValueBase[][]; };
	protected range: {row: number, col: number, rowspan: number, colspan: number} = {row: 0, col: 0, rowspan: 0, colspan: 0}
	constructor(
		@InjectByName('TableDatas') protected tableDatas: ITableDatas
	) {

	}
	protected updateSelfRange(_start: IAllPosition, _end: IAllPosition) {
		if(_start.type === 'position' && _end.type === 'position') {
			let start = _start as IPosition, end = _end as IPosition;
			if(start.row > end.row || start.col > end.col) {
				let temp = start;
				start = end;
				end = temp;
			}
			this.range = {
				row: start.row,
				col: start.col,
				rowspan: end.row - start.row + 1,
				colspan: end.col - start.col + 1
			}
		}
		if(_start.type === 'rowPosition' && _end.type === 'rowPosition') {
			let start = _start as IPositionFullRow, end = _end as IPositionFullRow;
			if(start.value > end.value) {
				let temp = start;
				start = end;
				end = temp;
			}
			this.range = {
				row: start.value,
				col: -1,
				rowspan: end.value - start.value + 1,
				colspan: -1
			}
		}
		if(_start.type === 'colPosition' && _end.type === 'colPosition') {
			let start = _start as IPositionFullCol, end = _end as IPositionFullCol;
			if(start.value > end.value) {
				let temp = start;
				start = end;
				end = temp;
			}
			this.range = {
				row: -1,
				rowspan: -1,
				col: start.value,
				colspan: end.value - start.value + 1
			}
		}
	}
	public setValue(start: IAllPosition, end: IAllPosition) {
		if (start.type !== end.type && !(start.type !== 'position' && start.type !== 'rowPosition' && start.type !== 'colPosition')) {
			throw new FormulaError('#VALUE!', { errorId: '664a5a221a43' });
		}
		this.updateSelfRange(start, end);
		let startRow = 0, endRow = 0,startCol = 0,endCol = 0;
		if(start.type == 'position') {
			if(start.row >= (end as IPosition).row && start.col >= (end as IPosition).col) {
				let temp = start;
				start = end;
				end = temp;
			}
			startRow = (start as IPosition).row;
			endRow = (end as IPosition).row;
			startCol = (start as IPosition).col;
			endCol = (end as IPosition).col;
		}
		if(start.type === 'rowPosition') {
			let _start = start as IPositionFullRow;
			let _end = end as IPositionFullRow;
			if(_start.value > _end.value) {
				let temp = _start;
				_start = _end;
				_end = temp;
			}
			startRow = _start.value;
			endRow = _end.value;
			startCol = 0;
			endCol = Infinity;
		}
		if(start.type === 'colPosition') {
			let _start = start as IPositionFullCol;
			let _end = end as IPositionFullCol;
			if(_start.value > _end.value) {
				let temp = _start;
				_start = _end;
				_end = temp;
			}
			startRow = 0;
			endRow = Infinity;
			startCol = _start.value;
			endCol = _end.value;
		}
		this.value = {
			getMatrixValues: () => {
				let result: IValueBase[][] = [];
				for(let i = startRow; i < (this.tableDatas.getMaxRow() + 1) || i < endRow + 1; i++) {
					let rowDatas: IValueBase[] = [];
					
					if(!this.tableDatas.rowIsExist(i)) {
						result.push(rowDatas);
						continue;
					}
					let rowInstance = this.tableDatas.getRow(i);
					for(let j = startCol; j < (rowInstance.getMaxCol() + 1) || j < endCol; j++) {
						if(!rowInstance.colIsExist(j)) {
							rowDatas[j] = { type: 'empty'};
							continue;
						}
						rowDatas[j] = this.formatCellValue(rowInstance.getCell(j));
					}
					result.push(rowDatas);
				}
				return result;
			},
			getValues: () => {
				let result: IValueBase[] = [];
				// console.log(this.tableDatas.getMaxRow(), endRow)
				for(let i = startRow; i < (this.tableDatas.getMaxRow() + 1) && i < endRow + 1; i++) {
					if(!this.tableDatas.rowIsExist(i)) {
						continue;
					}
					let rowInstance = this.tableDatas.getRow(i);
					for(let j = startCol; j < (rowInstance.getMaxCol() + 1) && j < endCol + 1; j++) {
						if(!rowInstance.colIsExist(j)) {
							continue;
						}
						result.push(this.formatCellValue(rowInstance.getCell(j)));
					}
				}
				return result;
			}
		}
	}
	protected formatCellValue(cell: Cell|null): IValueBase {
		if(cell && (cell.value.getActualValue().type !== 'empty' || cell.value.getActualValue().type !== 'ERROR') ) {
		  let value = cell.value.getActualValue();
			if(typeof value === 'object') {
				return value as any;
			}
		  if(typeof value === 'boolean') {
			return {
			  type: 'value',
			  dataType: 'boolean',
			  value: value
			}
		  }
		  if(typeof value === 'string' && isNaN(Number(value))) {
			return {
			  type: 'value',
			  dataType: 'string',
			  value: value
			}
		  }
		  if((typeof value === 'string' || typeof value === 'number') && !isNaN(Number(value))) {
			return {
			  type: 'value',
			  dataType: 'number',
			  value: Number(value)
			}
		  }
		} else {
		  return null;
		}
	  }
}

